
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;

//svnkit imports
using org.tmatesoft.svn.core;
using org.tmatesoft.svn.core.wc;

namespace Subsync.Core.Subversion
{
	
	
	public class SVNAdd : CommandBase
	{
        /// <summary>
        /// We have our variables declared here.
        /// Access modifiers as you can observe, is public. Why?
        /// Because we trust our programmers.
        /// 
        /// Try to be verbose with the variable names.
        /// Also, try to include *sane defaults*. Take peg_revision for eg.
        /// </summary>

        public java.io.File path;
        public java.io.File[] paths;
        public bool force = false;
        public bool mkdir;
        public bool climbUnversionedParents;
        public SVNDepth depth = SVNDepth.INFINITY;
        public bool includeIgnored = false;
        public bool makeParents;
        public bool depthIsSticky;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SVNAdd()
        {
        }

        /// <summary>
		/// Minimal constructor for unit tests.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/>
		/// </param>
		public SVNAdd(string path)
		{
		}

        /// <summary>
        /// Minimal constructor
        /// </summary>
        /// <param name="path">
        /// A <see cref="java.io.File"/>
        /// </param>
        /// <param name="force">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="climbUnversionedParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="depth">
        /// A <see cref="SVNDepth"/>
        /// </param>
        /// <param name="includeIgnored">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="makeParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        public SVNAdd(java.io.File path, bool force, bool mkdir, bool climbUnversionedParents, SVNDepth depth, bool includeIgnored, bool makeParents)
        {
            this.path = path;
            this.force = force;
            this.climbUnversionedParents = climbUnversionedParents;
            this.depth = depth;
            this.includeIgnored = includeIgnored;
            this.makeParents = makeParents;
        }

        /// <summary>
        /// Depth-sticky constructor
        /// </summary>
        /// <param name="path">
        /// A <see cref="java.io.File"/>
        /// </param>
        /// <param name="force">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="climbUnversionedParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="depth">
        /// A <see cref="SVNDepth"/>
        /// </param>
        /// <param name="depthIsSticky">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="includeIgnored">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="makeParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        public SVNAdd(java.io.File path, bool force, bool mkdir, bool climbUnversionedParents, SVNDepth depth, bool depthIsSticky, bool includeIgnored, bool makeParents)
        {
            this.path = path;
            this.force = force;
            this.climbUnversionedParents = climbUnversionedParents;
            this.depth = depth;
            this.depthIsSticky = depthIsSticky;
            this.includeIgnored = includeIgnored;
            this.makeParents = makeParents;
        }

        /// <summary>
        /// Depth-sticky constructor for multiple files
        /// </summary>
        /// <param name="paths">
        /// A <see cref="java.io.File[]"/>
        /// </param>
        /// <param name="force">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="climbUnversionedParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="depth">
        /// A <see cref="SVNDepth"/>
        /// </param>
        /// <param name="depthIsSticky">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="includeIgnored">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="makeParents">
        /// A <see cref="System.Boolean"/>
        /// </param>
        public SVNAdd(java.io.File[] paths, bool force, bool mkdir, bool climbUnversionedParents, SVNDepth depth, bool depthIsSticky, bool includeIgnored, bool makeParents)
        {
            this.paths = paths;
            this.force = force;
            this.climbUnversionedParents = climbUnversionedParents;
            this.depth = depth;
            this.depthIsSticky = depthIsSticky;
            this.includeIgnored = includeIgnored;
            this.makeParents = makeParents;
        }

        public override void Execute()
		{
            //DEBUG MSG. *Always* include this.
            Debug.WriteLine("SVN Add Execution");

            //library setup
            Tools.setupLibrary();

            //load up the clients
            SVNClientManager cm = SVNClientManager.newInstance();
            SVNWCClient wcc = cm.getWCClient();

            try
            {
                wcc.doAdd(this.path, this.force, this.mkdir, this.climbUnversionedParents, 
                    this.depth, this.includeIgnored, this.makeParents);
            }
            catch (SVNException e)
            {
                //we convert this exception to a non SVNKit exception.
                //we want to minimize interfacing with SVNkit outside of this namespace (abstraction)
                throw new SVNExecuteException(e.getMessage());
            }
		}
		
        public override Dictionary<string, List<object>> getTokens()
        {
            Dictionary<string, List<object>> ret = new Dictionary<string, List<object>>();
            ret.Add("add", new List<object>() { "add" });
            return ret;
        }

        public override List<KeyValuePair<string, initPointer>> getInitPointers()
        {
            List<KeyValuePair<string, initPointer>> ret = new List<KeyValuePair<string, initPointer>>();
            ret.Add(new KeyValuePair<string, initPointer>("add", new initPointer(this.handleCLI)));
            return ret;
        }

        public void handleCLI(Dictionary<string, List<object>> tokens)
        {
            if (tokens["add"].Count != 1)
            {
                Console.WriteLine("Not enough arguments: Commit requires at least 1 arguments (file/folder location)");
                return;
            }

            string location = (string)tokens["add"][0];
            this.path = new java.io.File(location);
            this.Execute();

        }
	}
}
